﻿using System;
using System.Collections.Generic;
using JetBrains.Application;
using JetBrains.ProjectModel;
using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.Caches;
using JetBrains.ReSharper.Psi.Tree;
using JetBrains.ReSharper.UnitTestExplorer;
using JetBrains.Util;

namespace Objectware.Silverlight.Testing.Runner.Resharper.Elements
{
	public abstract class TestElement : UnitTestElement
	{
		private ProjectModelElementEnvoy ProjectEnvoy { get; set; }
		private string TypeName { get; set; }

        protected TestElement(IUnitTestProvider provider,
                                   UnitTestElement parent,
                                   IProjectModelElement project,
                                   string typeName)
            : base(provider, parent)
        {
			if (null != project)
			{
				this.ProjectEnvoy = new ProjectModelElementEnvoy(project);
			}

        	this.TypeName = typeName;
        }


		public abstract bool IsNameIdentical(TestElement element);

		public override bool Equals(object obj)
		{
			if (base.Equals(obj))
			{
				TestElement element = (TestElement)obj;

				if (Equals(element.ProjectEnvoy, this.ProjectEnvoy))
				{
					return (element.TypeName == this.TypeName);
				}
			}

			return false;
		}
	

		protected ITypeElement GetDeclaredType()
		{
			IProject project = GetProject();
			if (project == null)
				return null;

			PsiManager manager = PsiManager.GetInstance(project.GetSolution());

			using (ReadLockCookie.Create())
			{
				DeclarationsCacheScope scope = DeclarationsCacheScope.ProjectScope(project, true);
				IDeclarationsCache cache = manager.GetDeclarationsCache(scope, true);
				return cache.GetTypeElementByCLRName(this.TypeName);
			}
		}

		public override UnitTestElementDisposition GetDisposition()
		{
			IDeclaredElement element = GetDeclaredElement();
			if (element == null || !element.IsValid())
			{
				return UnitTestElementDisposition.ourInvalidDisposition;
			}

			List<UnitTestElementLocation> locations = new List<UnitTestElementLocation>();

			foreach (IDeclaration declaration in element.GetDeclarations())
			{
				IFile file = declaration.GetContainingFile();

				if (file != null)
				{
					locations.Add(new UnitTestElementLocation(file.ProjectFile,
					                                          declaration.GetNameRange(),
					                                          declaration.GetDocumentRange().TextRange));
				}
			}

			return new UnitTestElementDisposition(locations, this);
		}

		public override UnitTestNamespace GetNamespace()
		{
			return new UnitTestNamespace(new CLRTypeName(this.TypeName).NamespaceName);
		}

		public override IProject GetProject()
		{
			return this.ProjectEnvoy.GetValidProjectElement() as IProject;
		}

		public override IList<IProjectFile> GetProjectFiles()
		{
			ITypeElement type = GetDeclaredType();
			if (type == null)
			{
				return EmptyArray<IProjectFile>.Instance;
			}

			return type.GetProjectFiles();
		}

		public override string GetTitle()
		{
			return "";
		}

		public override string GetTypeClrName()
		{
			return this.TypeName;
		}
	}
}
